#ifndef __STDF_TYPES_H__
#define __STDF_TYPES_H__

#include <string>
#include <vector>
#include <ostream>

using namespace std;

namespace stdf {

    enum ByteOrder
    {
        NotDefined   = 0,
        BigEndian    = 4321,
        LittleEndian = 1234,
        PDPEndian    = 3412
    };

    enum RecordType
    {
        Header=0,
        FAR=10, ATR=20,
        MIR=110, MRR=120, PCR=130, HBR=140, SBR=150, PMR=160, PGR=162, PLR=163, RDR=170, SDR=180,
        WIR=210, WRR=220, WCR=230,
        PIR=510, PRR=520,
        TSR=1030,
        PTR=1510, MPR=1515, FTR=1520,
        BPS=2010, EPS=2020,
        GDR=5010, DTR=5030,
        Reserved=9999
    };

    enum RWMode { None, ReadOnly, WriteOnly = 2 };

    typedef unsigned int   UINT;

    typedef unsigned char  UCHAR;
    typedef unsigned short USHORT;
    typedef unsigned long  ULONG;

    typedef unsigned char  U1; // one byte  on 32bit and 64bit machines
    typedef unsigned short U2; // two bytes on 32bit and 64bit machines
    typedef char           I1;
    typedef short          I2;
    #if (MACHTYPE == x86_64)
    // 64bit
        typedef unsigned int   U4;
        typedef int            I4;
    #else
    // Assume 32bit
        typedef unsigned long  U4;
        typedef long           I4;
    #endif

    typedef float          R4;
    typedef double         R8;

    typedef char           C1;
    typedef unsigned char  B1;
    typedef unsigned char  N1;


    typedef unsigned char  uchar;

    class CN     {
    public:
        CN(void);
        U2 getLength(void);
        CN& operator= (string s);
        void set(string s);
        bool isValid(void);
//        U2 operator+(U2 num);
        friend ostream& operator<<(ostream& os, CN& cn);
        string str(void) { return _str; }

    public:
        string _str;
    };


// \brief  D*n     Variable length bit-encoded field           char[]
//
// First two bytes = unsigned count of bits to follow
// (maximum of 65,535 bits)
// First data item in least significant bit of the
// third byte of the array (first two bytes are count)
// Unused bits at the high order end of the last byte
// must be zero.
    class DN
    {
    public:
        DN(void);
        U2 getLength(void); // Returns the number of bytes
        U2 getCount(void)
        {
            return count;
        }
        void set(U2& newCount, std::vector<U1>& newData) { count = newCount; data = newData; }
        U2 getNumBytes(void) {
            U2 numBytes = (U2) ((count / 8) + 1);
            if((count % 8) == 0) numBytes--;
            return numBytes;
        }

        friend ostream& operator<<(ostream& os, DN& cn);
    public:
        U2 count; // count for the number of bits
        std::vector<U1> data;
    };

/////////////////////////////////////////////////////////////////////////
//
//  B*n     Variable length bit-encoded field
//          First byte = unsigned count of bytes to follow (max. 255)
//          First data item in least significant bit of the second
//          byte of the array (first byte is count)
//
    class BN
    {
    public:
        BN(void);
        U2 getLength(void);
        BN& operator=(vector<U1> values);

        friend ostream& operator<<(ostream& os, BN& bn);
    public:
        U1 count;
        std::vector<U1> data;
    };

    class VN
    {
    public:
        VN(void);
        U2 getLength(void); // Returns the number of bytes

        friend ostream& operator<<(ostream& os, VN& gd);
    public:
        U1 code;
        union
        {
            U1 u1;
            U2 u2;
            U4 u4;
            I1 i1;
            I2 i2;
            I4 i4;
            R4 r4;
            R8 r8;
            N1 n1;
        };
        CN cn;
        BN bn;
        DN dn;
    };

} // end namespace

#endif

// \brief STDF Data Types
// -----------|----------------------------------------|-----------------------
//    Code    | Description                            | C Type Specifier
// -----------|----------------------------------------|-----------------------
//    C*12    | Fixed length character string          | char[12]
//            | If a fixed length char string does not |
//            | fill the entire field, it must be left |
//            | justified and padded with spaces.      |
//    C*n     | Variable length character string       |
//    C*f     | Variable length character string       | char[]
//    U*1     | One byte unsigned integer              | unsigned char
//    U*2     | Two byte unsigned integer              | unsigned short
//    U*4     | Four byte unsigned integer             | unsigned long
//    I*1     | One byte signed integer                | char
//    I*2     | Two byte signed integer                | short
//    I*4     | Four byte signed integer               | long
//    R*4     | Four byte floating point number        | float
//    R*8     | Eight byte floating point number       | long float (double)
//    B*6     | Fixed length bit-encoded data          | char[6]
//    V*n     | Variable data type field               |
//            | The data type is specified by a code   |
//            | in the first byte, and the data        |
//            | follows (max. of 255 bytes)            |
//    B*n     | Variable length bit-encoded field      |
//            | First byte = unsigned count of bytes   |
//            | to follow (max of 255 bytes)           |
//    D*n     | Variable length bit-encoded field      | char[]
//            | First two bytes = unsigned count       |
//            | of bits to follow (max. of 65535 bits) |
//            | First data item in least significant   |
//            | bit of the third byte of the array     |
//            | (first 2 bytes are count)              |
//    N*1     | Unsigned integer data stored in a      | char
//            | nibble. (Nibble = 4 bits of a byte)    |
//            | First item in low 4 bits, second item  |
//            | in high 4 bits.                        |
//    kxTYPE  | Arry of data of the type specified     | TYPE[]
//            | The value of 'k' (the number of        |
//            | elements in the array) is defined in   |
//            | an earlier field in the record.        |
// -----------|----------------------------------------|-----------------------




